﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArch.Utils;
using HYOpeningCommon.DataEnum;
using HYOpeningCommon.DbOpening;
using HYOpeningCommon.OpeningProfile;

namespace HYOpeningCommon.Public
{
	public class CommonInterface
	{
		public static bool CreateSketchPlane(Autodesk.Revit.DB.Document doc, XYZ normal, XYZ ori, ref SketchPlane sketchPlane)
		{
			Transaction transaction = new Transaction(doc, "CreatePlane");
			bool result;
			try
			{
				transaction.Start();
				Plane plane = RevitVersionFuncs.CreatePlanByNormalAndOrigin(normal, ori);
				sketchPlane = SketchPlane.Create(doc, plane);
				transaction.Commit();
				result = true;
			}
			catch (Exception)
			{
				transaction.RollBack();
				result = false;
			}
			return result;
		}

		public static bool CreateModelLine(List<XYZ> lstPt, Autodesk.Revit.DB.Document doc, SketchPlane sketchPlane, ref List<ElementId> lstElemId, ElementId elemId)
		{
			if (lstPt.Count != 4)
			{
				return false;
			}
			Transaction transaction = new Transaction(doc, "CreateCurve");
			bool result;
			try
			{
				transaction.Start();
				Line line = Line.CreateBound(lstPt[0], lstPt[1]);
				Line line2 = Line.CreateBound(lstPt[1], lstPt[2]);
				Line line3 = Line.CreateBound(lstPt[2], lstPt[3]);
				Line line4 = Line.CreateBound(lstPt[3], lstPt[0]);
				ModelLine modelLine = doc.Create.NewModelCurve(line, sketchPlane) as ModelLine;
				ModelLine modelLine2 = doc.Create.NewModelCurve(line2, sketchPlane) as ModelLine;
				ModelLine modelLine3 = doc.Create.NewModelCurve(line3, sketchPlane) as ModelLine;
				ModelLine modelLine4 = doc.Create.NewModelCurve(line4, sketchPlane) as ModelLine;
				Element element = doc.GetElement(elemId);
				modelLine.LineStyle = element;
				modelLine2.LineStyle = element;
				modelLine3.LineStyle = element;
				modelLine4.LineStyle = element;
				lstElemId.Add(modelLine.Id);
				lstElemId.Add(modelLine2.Id);
				lstElemId.Add(modelLine3.Id);
				lstElemId.Add(modelLine4.Id);
				transaction.Commit();
				result = true;
			}
			catch (Exception)
			{
				transaction.Commit();
				result = false;
			}
			return result;
		}

		public static bool CreateModelCurve(double radius, Autodesk.Revit.DB.Document doc, Plane plane, ref List<ElementId> lstElemId, ElementId elemId)
		{
			Transaction transaction = new Transaction(doc, "CreateModelCurve");
			bool result;
			try
			{
				transaction.Start();
				SketchPlane sketchPlane = SketchPlane.Create(doc, plane);
				if (sketchPlane == null)
				{
					transaction.RollBack();
					result = false;
				}
				else
				{
					Arc arc = Arc.Create(plane, radius * 2.0, 0.0, Math.PI*2);
					ModelArc modelArc = doc.Create.NewModelCurve(arc, sketchPlane) as ModelArc;
					Element element = doc.GetElement(elemId);
					modelArc.LineStyle = element;
					lstElemId.Add(modelArc.Id);
					transaction.Commit();
					result = true;
				}
			}
			catch (Exception)
			{
				transaction.RollBack();
				result = false;
			}
			return result;
		}

		public static void GetPreViewStyle(ref GraphicsStyle greenGraphicsStyle, Autodesk.Revit.DB.Document doc)
		{
            greenGraphicsStyle = CommonInterface.GetLineStyle(doc, "HYGreenLineStyle", new Autodesk.Revit.DB.Color(0, byte.MaxValue, 0), 5);
		}

        public static GraphicsStyle GetLineStyle(Autodesk.Revit.DB.Document doc, string strLineTypeName, Autodesk.Revit.DB.Color color, int iLineWeight = 5)
		{
			Category category = doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines);
			if (category == null)
			{
				return null;
			}
			if (!category.SubCategories.Contains(strLineTypeName))
			{
				Transaction transaction = new Transaction(doc, "new line style");
				try
				{
					transaction.Start();
					Category category2 = doc.Settings.Categories.NewSubcategory(category, strLineTypeName);
					category2.LineColor = color;
					category2.SetLineWeight(iLineWeight, (Autodesk.Revit.DB.GraphicsStyleType)1);
					transaction.Commit();
				}
				catch (Exception)
				{
					if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
					{
						transaction.RollBack();
					}
					return null;
				}
			}
			foreach (Element element in new FilteredElementCollector(doc).OfClass(typeof(GraphicsStyle)))
			{
				GraphicsStyle graphicsStyle = element as GraphicsStyle;
				if (graphicsStyle != null && graphicsStyle.Name.CompareTo(strLineTypeName) == 0)
				{
					return graphicsStyle;
				}
			}
			return null;
		}

		public static void SetView3DChanged(UIDocument uiDoc)
		{
			View3D hy3DView = DBOper3DView.GetHY3DView(uiDoc);
			DBOper3DView.SetViewStyle(ref hy3DView, uiDoc);
			DBOper3DView.SetViewCutVisible(ref hy3DView, uiDoc.Document);
		}

		public static void DoubleClick2Location(DbOpeningBase dbOpeningBase, UIDocument uiDoc)
		{
			Element element = null;
			List<Element> list = new List<Element>();
			if (dbOpeningBase.m_idModelGroup != null)
			{
				element = uiDoc.Document.GetElement(dbOpeningBase.m_idModelGroup);
				if (element == null)
				{
					return;
				}
				list.Add(element);
				RevitVersionFuncs.SetSelection(uiDoc.Selection, list);
			}
			UIView uiview = null;
			foreach (UIView uiview2 in uiDoc.GetOpenUIViews())
			{
				if (uiview2.ViewId.Equals(uiDoc.ActiveView.Id))
				{
					uiview = uiview2;
					break;
				}
			}
			BoundingBoxXYZ boundingBoxXYZ = null;
			if (element != null)
			{
				boundingBoxXYZ = element.get_BoundingBox(uiDoc.Document.ActiveView);
				XYZ xyz = boundingBoxXYZ.Min;
				XYZ xyz2 = boundingBoxXYZ.Max;
				XYZ xyz3 = (xyz2 - xyz).Normalize();
				xyz += xyz3.Negate() * 7.0;
				xyz2 += xyz3 * 7.0;
				uiview.ZoomAndCenterRectangle(xyz, xyz2);
			}
			CommonInterface.SetSectionBox(uiDoc.Document, dbOpeningBase, boundingBoxXYZ);
		}

		private static void SetSectionBox(Autodesk.Revit.DB.Document doc, DbOpeningBase dbOpeningBase, BoundingBoxXYZ box3D)
		{
			Transaction transaction = new Transaction(doc, "ModifyView3DHeight");
			try
			{
				View3D view3D = doc.ActiveView as View3D;
				if (view3D != null)
				{
					transaction.Start();
					if (view3D.IsSectionBoxActive)
					{
						view3D.IsSectionBoxActive = false;
					}
					BoundingBoxXYZ sectionBox = view3D.GetSectionBox();
					Transform transform = sectionBox.Transform;
					XYZ position = dbOpeningBase.m_profile.m_position;
					XYZ xyz = sectionBox.Max;
					xyz = transform.OfPoint(xyz);
					double num = 0.5;
					if (dbOpeningBase.m_eHostObject == EHostObject.eStruFloor)
					{
						double num2 = position.Z + dbOpeningBase.m_dHostWidth / 2.0 + num;
						xyz = new XYZ(xyz.X, xyz.Y, num2);
					}
					else
					{
						OpeningProfileBase profile = dbOpeningBase.m_profile;
						if (profile is OpeningProfileCircle)
						{
							OpeningProfileCircle openingProfileCircle = profile as OpeningProfileCircle;
							double num3 = position.Z + openingProfileCircle.m_dCutDiameter / 2.0 + num;
							xyz = new XYZ(xyz.X, xyz.Y, num3);
						}
						else if (profile is OpeningProfileRect)
						{
							OpeningProfileRect openingProfileRect = profile as OpeningProfileRect;
							double num4 = position.Z + openingProfileRect.m_cutHeight / 2.0 + num;
							xyz = new XYZ(xyz.X, xyz.Y, num4);
						}
						else if (profile is OpeningProfileEquipRect)
						{
							OpeningProfileEquipRect openingProfileEquipRect = profile as OpeningProfileEquipRect;
							double num5 = position.Z + openingProfileEquipRect.m_dHeight + num;
							xyz = new XYZ(xyz.X, xyz.Y, num5);
						}
					}
					xyz = transform.Inverse.OfPoint(xyz);
					XYZ max = xyz;
					XYZ xyz2 = sectionBox.Min;
					double num6 = 100.0;
					while (box3D.Min.X > xyz.X)
					{
						xyz = (max = new XYZ(box3D.Max.X + num6, xyz.Y, xyz.Z));
					}
					while (box3D.Min.Y > xyz.Y)
					{
						xyz = (max = new XYZ(xyz.X, box3D.Max.Y + num6, xyz.Z));
					}
					while (box3D.Max.X < xyz2.X)
					{
						xyz2 = new XYZ(box3D.Min.X - num6, xyz2.Y, xyz2.Z);
					}
					while (box3D.Max.Y < xyz2.Y)
					{
						xyz2 = new XYZ(xyz2.X, box3D.Min.Y - num6, xyz2.Z);
					}
					while (box3D.Max.Z < xyz2.Z)
					{
						xyz2 = new XYZ(xyz2.X, xyz2.Y, box3D.Min.Z - num6);
					}
					sectionBox.Max = max;
					sectionBox.Min = xyz2;
					view3D.SetYJKSectionBox(sectionBox);
					view3D.IsSectionBoxActive = true;
					transaction.Commit();
				}
			}
			catch (Exception)
			{
				transaction.RollBack();
			}
		}

		public static List<Document> GetLinkDocs(Autodesk.Revit.DB.Document doc)
		{
			List<Document> result;
			try
			{
				List<Document> list = new List<Document>();
				foreach (RevitLinkInstance revitLinkInstance in ((IEnumerable<RevitLinkInstance>)new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance)).WhereElementIsNotElementType().Cast<RevitLinkInstance>().ToList<RevitLinkInstance>()))
				{
					Document linkDocument = revitLinkInstance.GetLinkDocument();
					if (linkDocument != null)
					{
						list.Add(linkDocument);
					}
				}
				result = list;
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		public static List<RevitLinkInstance> GetLinkRevitIns(Autodesk.Revit.DB.Document doc)
		{
			List<RevitLinkInstance> result;
			try
			{
				result = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance)).WhereElementIsNotElementType().Cast<RevitLinkInstance>().ToList<RevitLinkInstance>();
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		public static Element GetElemByUniqueId(Autodesk.Revit.DB.Document doc, string uniqueId)
		{
			List<Document> linkDocs = CommonInterface.GetLinkDocs(doc);
			linkDocs.Add(doc);
			foreach (Autodesk.Revit.DB.Document document in linkDocs)
			{
				Element element = document.GetElement(uniqueId);
				if (element != null)
				{
					return element;
				}
			}
			return null;
		}

		public static int GetArcWallCurve(Autodesk.Revit.DB.Document doc, string uniqueId, ref Curve curve, ref XYZ normal)
		{
			Element elemByUniqueId = CommonInterface.GetElemByUniqueId(doc, uniqueId);
			if (elemByUniqueId == null)
			{
				return -1;
			}
			Wall wall = elemByUniqueId as Wall;
			if (wall == null)
			{
				return -1;
			}
			Curve curve2 = (wall.Location as LocationCurve).Curve;
			if (curve2 is Arc && wall.UniqueId == uniqueId)
			{
				curve = curve2;
				return 1;
			}
			if (curve2 is Line && wall.UniqueId == uniqueId)
			{
				normal = wall.Orientation.Normalize();
				return 0;
			}
			return -1;
		}

		private static bool FindFloorFace(Floor floor, ref List<Face> lstFace, Curve curve)
		{
			try
			{
				foreach (GeometryObject geometryObject in floor.get_Geometry(new Options
				{
					ComputeReferences = true,
                    DetailLevel = (ViewDetailLevel)3
				}))
				{
					if (geometryObject is Solid)
					{
						foreach (object obj in (geometryObject as Solid).Faces)
						{
							Face face = (Face)obj;
							IntersectionResultArray intersectionResultArray = null;
                            if ((int)face.Intersect(curve, out intersectionResultArray) == 8)
							{
								UV uvpoint = intersectionResultArray.get_Item(0).UVPoint;
								XYZ xyz = face.ComputeNormal(uvpoint);
								if (Geometry.LessThan(XYZ.BasisZ.AngleTo(xyz.Normalize()), Math.PI*.5))
								{
									lstFace.Add(face);
								}
							}
						}
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		public static List<XYZ> GetCvIntersect2FloorPoints(Curve cv, Element elem)
		{
			List<XYZ> list = new List<XYZ>();
			try
			{
				if (elem is Floor)
				{
					Floor floor = elem as Floor;
					List<Face> list2 = new List<Face>();
					if (!CommonInterface.FindFloorFace(floor, ref list2, cv) || list2.Count == 0)
					{
						return null;
					}
					Line line = cv as Line;
					if (line == null)
					{
						return null;
					}
					using (List<Face>.Enumerator enumerator = list2.GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							if (!CommonInterface.LineIntersectPlaneFace(enumerator.Current, line, ref list))
							{
								return null;
							}
						}
					}
					if (list.Count == 0)
					{
						return null;
					}
				}
			}
			catch (Exception)
			{
				return null;
			}
			return list;
		}

		private static bool LineIntersectPlaneFace(Face face, Line line, ref List<XYZ> lstPts)
		{
			try
			{
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				SetComparisonResult setComparisonResult = face.Intersect(line, out intersectionResultArray);
				if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
				{
					for (int i = 0; i < intersectionResultArray.Size; i++)
					{
						lstPts.Add(intersectionResultArray.get_Item(i).XYZPoint);
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		public static XYZ GetOpeningPosition(XYZ pt, Element elem)
		{
			Curve curve = Line.CreateUnbound(pt, XYZ.BasisZ);
			if (curve == null)
			{
				return null;
			}
			List<XYZ> cvIntersect2FloorPoints = CommonInterface.GetCvIntersect2FloorPoints(curve, elem);
			if (cvIntersect2FloorPoints == null || cvIntersect2FloorPoints.Count == 0)
			{
				return null;
			}
			return cvIntersect2FloorPoints[0];
		}

		public static bool GetCurveOritation(XYZ location, Curve curve, ref XYZ normal)
		{
			bool result;
			try
			{
				if (location == null || curve == null)
				{
					result = false;
				}
				else
				{
					IntersectionResult intersectionResult = curve.Project(location);
					if (intersectionResult == null)
					{
						result = false;
					}
					else
					{
						double parameter = intersectionResult.Parameter;
						XYZ basisX = curve.ComputeDerivatives(parameter, false).BasisX;
						normal = XYZ.BasisZ.CrossProduct(basisX).Normalize();
						result = true;
					}
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		[DllImport("user32.dll")]
		public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public static void KeyEsc(IntPtr handle)
		{
			int bVk = 27;
			int dwFlags = 0;
			int dwFlags2 = 2;
			int wMsg = 7;
			CommonInterface.SendMessage(handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			CommonInterface.keybd_event((byte)bVk, 0, dwFlags, 0);
			CommonInterface.keybd_event((byte)bVk, 0, dwFlags2, 0);
		}

		public static double GetPipe2WallHAng(XYZ DirectionCutObj, XYZ DirectionProfile, XYZ Position)
		{
			Plane planeProj = RevitVersionFuncs.CreatePlanByNormalAndOrigin(XYZ.BasisZ, Position);
			XYZ xyz = CommonInterface.CalcProjPointByPlane(Position + DirectionCutObj.Normalize(), planeProj) - Position;
			if (xyz.AngleTo(DirectionProfile) > Math.PI*.5)
			{
				xyz = -xyz;
			}
			XYZ xyz2 = DirectionProfile.CrossProduct(XYZ.BasisZ);
			return xyz.AngleTo(xyz2);
		}

		public static double GetPipe2WallVAng(XYZ DirectionCutObj, XYZ DirectionProfile, XYZ Position)
		{
			Plane planeProj = RevitVersionFuncs.CreatePlanByNormalAndOrigin(DirectionProfile.CrossProduct(XYZ.BasisZ), Position);
			XYZ xyz = CommonInterface.CalcProjPointByPlane(Position + DirectionCutObj.Normalize(), planeProj) - Position;
			if (xyz.AngleTo(DirectionProfile) > Math.PI*.5)
			{
				xyz = -xyz;
			}
			return xyz.AngleTo(XYZ.BasisZ);
		}

		private static XYZ CalcProjPointByPlane(XYZ ptTest, Plane planeProj)
		{
			return (Transform.CreateReflection(planeProj).OfPoint(ptTest) + ptTest) * 0.5;
		}

		public static void GetMinMaxVal(List<XYZ> lstPt, ref XYZ ptMin, ref XYZ ptMax)
		{
			double val = double.MinValue;
			double val2 = double.MaxValue;
			double num = 0.0;
			double num2 = 0.0;
			double num3 = 0.0;
			double num4 = 0.0;
			double num5 = 0.0;
			double num6 = 0.0;
			foreach (XYZ xyz in lstPt)
			{
				if (Geometry.LessThan(xyz.X, val2))
				{
					val2 = xyz.X;
					num = xyz.X;
				}
				if (Geometry.LessThan(val, xyz.X))
				{
					val = xyz.X;
					num2 = xyz.X;
				}
			}
			val = double.MinValue;
			val2 = double.MaxValue;
			foreach (XYZ xyz2 in lstPt)
			{
				if (Geometry.LessThan(xyz2.Y, val2))
				{
					val2 = xyz2.Y;
					num4 = xyz2.Y;
				}
				if (Geometry.LessThan(val, xyz2.Y))
				{
					val = xyz2.Y;
					num3 = xyz2.Y;
				}
			}
			val = double.MinValue;
			val2 = double.MaxValue;
			foreach (XYZ xyz3 in lstPt)
			{
				if (Geometry.LessThan(xyz3.Z, val2))
				{
					val2 = xyz3.Z;
					num5 = xyz3.Z;
				}
				if (Geometry.LessThan(val, xyz3.Z))
				{
					val = xyz3.Z;
					num6 = xyz3.Z;
				}
			}
			ptMin = new XYZ(num, num4, num5);
			ptMax = new XYZ(num2, num3, num6);
		}

		public static EHostObject GetSubjectObj(Element elem)
		{
			if (elem is Wall)
			{
				Wall wall = elem as Wall;
				Document document = elem.Document;
				Parameter parameter = wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT);
				if (parameter != null && parameter.AsInteger() == 1)
				{
					return EHostObject.eStruWall;
				}
				foreach (ElementId elementId in wall.GetMaterialIds(false))
				{
					Material material = document.GetElement(elementId) as Material;
					if (material != null)
					{
						string name = material.Name;
						if (Regex.IsMatch(name, "混凝土") && !name.Contains("蒸汽加气混凝土") && !name.Contains("轻集料混凝土") && !name.Contains("素混凝土") && !name.Contains("陶粒混凝土") && !name.Contains("混凝土砌块"))
						{
							return EHostObject.eStruWall;
						}
					}
				}
				return EHostObject.eArchWall;
			}
			else
			{
				if (elem is Floor)
				{
					return EHostObject.eStruFloor;
				}
				return EHostObject.eUnKnown;
			}
		}

		public static void TransformElev2Relative(List<Level> lstLevel, ref double dElev)
		{
			if (lstLevel == null || lstLevel.IsEmpty<Level>())
			{
				return;
			}
			double num = AssistFunc.feetToMM(lstLevel[0].Elevation) / 1000.0;
			if (Geometry.LessThan(dElev, num))
			{
				return;
			}
			double num2 = 0.0;
			foreach (Level level in lstLevel)
			{
				num = level.Elevation;
				num = AssistFunc.feetToMM(num) / 1000.0;
				if (!Geometry.Greaterthan_Or_Equal(dElev, num))
				{
					dElev -= num2;
					return;
				}
				num2 = num;
			}
			dElev -= num2;
		}
	}
}
